/*
 * Copyright 2010 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package de.aformatik.android.apps.jfs.de.ui;

import de.aformatik.android.apps.jfs.R;
import de.aformatik.android.apps.jfs.de.service.SyncService;
import de.google.android.apps.iosched.provider.ScheduleContract.Blocks;
import de.google.android.apps.iosched.provider.ScheduleContract.Rooms;
import de.google.android.apps.iosched.provider.ScheduleContract.Sessions;
import de.google.android.apps.iosched.provider.ScheduleContract.Speakers;
import de.google.android.apps.iosched.provider.ScheduleContract.Tracks;
import de.google.android.apps.iosched.provider.ScheduleContract.Vendors;
import de.google.android.apps.iosched.util.FractionalTouchDelegate;
import de.google.android.apps.iosched.util.NotifyingAsyncQueryHandler;
import de.google.android.apps.iosched.util.UIUtils;
import de.google.android.apps.iosched.util.NotifyingAsyncQueryHandler.AsyncQueryListener;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.util.EntityUtils;
import org.json.JSONObject;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.TabActivity;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.database.Cursor;
import android.graphics.RectF;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CompoundButton;
import android.widget.TabHost;
import android.widget.TextView;
import android.widget.CompoundButton.OnCheckedChangeListener;

/**
 * {@link Activity} that displays details about a specific
 * {@link Sessions#SESSION_ID}, as requested through {@link Intent#getData()}.
 */
public class SessionDetailActivity extends TabActivity implements AsyncQueryListener, OnCheckedChangeListener
{
	private static final String TAG = "SessionDetailActivity";

	/**
	 * Since {@link Sessions} can belong to multiple {@link Tracks}, the parent
	 * {@link Activity} can send this extra specifying a {@link Tracks}
	 * {@link Uri} that should be used for coloring the title-bar.
	 */
	public static final String EXTRA_TRACK = "de.google.android.iosched.extra.TRACK";

	private static final String MODERATOR_PACKAGE = "de.google.android.apps.moderator";

	private static final String TAG_SUMMARY = "summary";
	private static final String TAG_NOTES = "notes";
//	private static final String TAG_MODERATOR = "moderator";

	private String mSessionId;
	private Uri mSessionUri;

	private String mTitleString;
	private String mHashtag;
	private String mRoomId;

	private TextView mTitle;
	private TextView mSubtitle;
	private CompoundButton mStarred;

	private TextView mAbstract;
	private TextView mRequirements;

	private NotifyingAsyncQueryHandler mHandler;

	private boolean mSessionCursor = false;
	private boolean mSpeakersCursor = false;
	private boolean mHasSummaryContent = false;

	private Uri mModeratorUri;
	private Uri mWaveUri;

	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_session_detail);

		mTitle = (TextView) findViewById(R.id.session_title);
		mSubtitle = (TextView) findViewById(R.id.session_subtitle);
		mStarred = (CompoundButton) findViewById(R.id.star_button);

		mStarred.setFocusable(true);
		mStarred.setClickable(true);

		// Larger target triggers star toggle
		final View starParent = findViewById(R.id.list_item_session);
		FractionalTouchDelegate.setupDelegate(starParent, mStarred, new RectF(0.6f, 0f, 1f, 0.8f));

		mAbstract = (TextView) findViewById(R.id.session_abstract);
		mRequirements = (TextView) findViewById(R.id.session_requirements);

		final Intent intent = getIntent();
		mSessionUri = intent.getData();
		mSessionId = Sessions.getSessionId(mSessionUri);

		setupSummaryTab();
		setupNotesTab();

		// Start background queries to load session and track details
		final Uri trackUri = resolveTrackUri(intent);
		final Uri speakersUri = Sessions.buildSpeakersDirUri(mSessionId);

		mHandler = new NotifyingAsyncQueryHandler(getContentResolver(), this);
		mHandler.startQuery(SessionsQuery._TOKEN, mSessionUri, SessionsQuery.PROJECTION);
		mHandler.startQuery(TracksQuery._TOKEN, trackUri, TracksQuery.PROJECTION);
		mHandler.startQuery(SpeakersQuery._TOKEN, speakersUri, SpeakersQuery.PROJECTION);
	}

	/** Build and add "summary" tab. */
	private void setupSummaryTab()
	{
		final TabHost host = getTabHost();

		// Summary content comes from existing layout
		host.addTab(host.newTabSpec(TAG_SUMMARY).setIndicator(buildIndicator(R.string.session_summary))
				.setContent(R.id.tab_session_summary));
	}

	/** Build and add "notes" tab. */
	private void setupNotesTab()
	{
		final TabHost host = getTabHost();

		final Uri notesUri = Sessions.buildNotesDirUri(mSessionId);
		final Intent intent = new Intent(Intent.ACTION_VIEW, notesUri);
		intent.addCategory(Intent.CATEGORY_TAB);
		intent.putExtra(NotesActivity.EXTRA_SHOW_INSERT, true);

		// Notes content comes from reused activity
		host.addTab(host.newTabSpec(TAG_NOTES).setIndicator(buildIndicator(R.string.session_notes)).setContent(intent));
	}

	/** Build and add "moderator" tab. */
//	private void setupModeratorTab(Cursor sessionsCursor)
//	{
//		final TabHost host = getTabHost();
//
//		// Insert Moderator when available
//		final View moderatorBlock = findViewById(R.id.moderator_block);
//		final String moderatorLink = sessionsCursor.getString(SessionsQuery.MODERATOR_LINK);
//		final boolean validModerator = !TextUtils.isEmpty(moderatorLink);
//		if (validModerator)
//		{
//			mModeratorUri = Uri.parse(moderatorLink);
//
//			// Set link, but handle clicks manually
//			final TextView textView = (TextView) findViewById(R.id.moderator_link);
//			textView.setText(mModeratorUri.toString());
//			textView.setMovementMethod(null);
//			textView.setClickable(true);
//			textView.setFocusable(true);
//
//			// Start background fetch of moderator status
//			startModeratorStatusFetch(moderatorLink);
//
//			moderatorBlock.setVisibility(View.VISIBLE);
//		}
//		else
//		{
//			moderatorBlock.setVisibility(View.GONE);
//		}
//
//		// Insert Wave when available
//		final View waveBlock = findViewById(R.id.wave_block);
//		final String waveLink = sessionsCursor.getString(SessionsQuery.WAVE_LINK);
//		final boolean validWave = !TextUtils.isEmpty(waveLink);
//		if (validWave)
//		{
//			// Rewrite incoming Wave URL to punch through user-agent check
//			mWaveUri = Uri.parse(waveLink).buildUpon().appendQueryParameter("nouacheck", "1").build();
//
//			// Set link, but handle clicks manually
//			final TextView textView = (TextView) findViewById(R.id.wave_link);
//			textView.setText(mWaveUri.toString());
//			textView.setMovementMethod(null);
//			textView.setClickable(true);
//			textView.setFocusable(true);
//
//			waveBlock.setVisibility(View.VISIBLE);
//		}
//		else
//		{
//			waveBlock.setVisibility(View.GONE);
//		}
//
//		if (validModerator || validWave)
//		{
//			// Moderator content comes from existing layout
//			host.addTab(host.newTabSpec(TAG_MODERATOR).setIndicator(buildIndicator(R.string.session_interact))
//					.setContent(R.id.tab_session_moderator));
//		}
//	}

	/** Handle Moderator link. */
	public void onModeratorClick(View v)
	{
		boolean appPresent = false;
		try
		{
			final PackageManager pm = getPackageManager();
			final ApplicationInfo ai = pm.getApplicationInfo(MODERATOR_PACKAGE, 0);
			if (ai != null)
				appPresent = true;
		}
		catch (NameNotFoundException e)
		{
			Log.w(TAG, "Problem searching for moderator: " + e.toString());
		}

		if (appPresent)
		{
			// Directly launch intent when already installed
			startModerator();
		}
		else
		{
			// Otherwise suggest installing app from Market
			showDialog(R.id.dialog_moderator);
		}
	}

	/** Handle Wave link. */
	public void onWaveClick(View v)
	{
		showDialog(R.id.dialog_wave);
	}

	@Override
	protected Dialog onCreateDialog(int id)
	{
		switch (id)
		{
			case R.id.dialog_moderator:
			{
				return new AlertDialog.Builder(this).setTitle(R.string.dialog_moderator_title)
						.setIcon(android.R.drawable.ic_dialog_info).setMessage(R.string.dialog_moderator_message)
						.setNegativeButton(R.string.dialog_moderator_market, new ModeratorMarketClickListener())
						.setPositiveButton(R.string.dialog_moderator_web, new ModeratorStartClickListener())
						.setCancelable(true).create();
			}
			case R.id.dialog_wave:
			{
				return new AlertDialog.Builder(this).setTitle(R.string.dialog_wave_title)
						.setIcon(android.R.drawable.ic_dialog_info).setMessage(R.string.dialog_wave_message)
						.setNegativeButton(android.R.string.cancel, null)
						.setPositiveButton(android.R.string.ok, new WaveConfirmClickListener()).setCancelable(true)
						.create();
			}
		}
		
		return null;
	}

	private class ModeratorStartClickListener implements DialogInterface.OnClickListener
	{
		public void onClick(DialogInterface dialog, int which)
		{
			startModerator();
		}
	}

	private class ModeratorMarketClickListener implements DialogInterface.OnClickListener
	{
		public void onClick(DialogInterface dialog, int which)
		{
			final Uri marketUri = Uri.parse("http://market.android.com/search?q=pname:" + MODERATOR_PACKAGE);
			
			startActivity(new Intent(Intent.ACTION_VIEW, marketUri));
		}
	}

	private class WaveConfirmClickListener implements DialogInterface.OnClickListener
	{
		public void onClick(DialogInterface dialog, int which)
		{
			startWave();
		}
	}

	private void startModerator()
	{
		startActivity(new Intent(Intent.ACTION_VIEW, mModeratorUri));
	}

	private void startWave()
	{
		startActivity(new Intent(Intent.ACTION_VIEW, mWaveUri));
	}

	/**
	 * Build a {@link View} to be used as a tab indicator, setting the requested
	 * string resource as its label.
	 */
	private View buildIndicator(int textRes)
	{
		final TextView indicator = (TextView) getLayoutInflater()
				.inflate(R.layout.tab_indicator, getTabWidget(), false);
		
		indicator.setText(textRes);
		return indicator;
	}

	/**
	 * Derive {@link Tracks#CONTENT_ITEM_TYPE} {@link Uri} based on incoming
	 * {@link Intent}, using {@link #EXTRA_TRACK} when set.
	 */
	private Uri resolveTrackUri(Intent intent)
	{
		final Uri trackUri = intent.getParcelableExtra(EXTRA_TRACK);
		if (trackUri != null)
		{
			return trackUri;
		}
		else
		{
			return Sessions.buildTracksDirUri(mSessionId);
		}
	}

	/** {@inheritDoc} */
	public void onQueryComplete(int token, Object cookie, Cursor cursor)
	{
		if (token == SessionsQuery._TOKEN)
		{
			onSessionQueryComplete(cursor);
		}
		else if (token == TracksQuery._TOKEN)
		{
			onTrackQueryComplete(cursor);
		}
		else if (token == SpeakersQuery._TOKEN)
		{
			onSpeakersQueryComplete(cursor);
		}
		else
		{
			cursor.close();
		}
	}

	/** Handle {@link SessionsQuery} {@link Cursor}. */
	private void onSessionQueryComplete(Cursor cursor)
	{
		try
		{
			mSessionCursor = true;
			
			if (!cursor.moveToFirst())
				return;

			// Format time block this session occupies
			final long blockStart = cursor.getLong(SessionsQuery.BLOCK_START);
			final long blockEnd = cursor.getLong(SessionsQuery.BLOCK_END);
			final String roomName = cursor.getString(SessionsQuery.ROOM_NAME);
			final String subtitle = UIUtils.formatSessionSubtitle(blockStart, blockEnd, roomName, this);

			mTitleString = cursor.getString(SessionsQuery.TITLE);
			mTitle.setText(mTitleString);
			mSubtitle.setText(subtitle);

			mHashtag = cursor.getString(SessionsQuery.HASHTAG);
			
			if (TextUtils.isEmpty(mHashtag))
				mHashtag = "";

			mRoomId = cursor.getString(SessionsQuery.ROOM_ID);

			// Unregister around setting checked state to avoid triggering
			// listener since change isn't user generated.
			mStarred.setOnCheckedChangeListener(null);
			mStarred.setChecked(cursor.getInt(SessionsQuery.STARRED) != 0);
			mStarred.setOnCheckedChangeListener(this);

			final String sessionAbstract = cursor.getString(SessionsQuery.ABSTRACT);
			
			if (!TextUtils.isEmpty(sessionAbstract))
			{
				UIUtils.setTextMaybeHtml(mAbstract, sessionAbstract);
				mAbstract.setVisibility(View.VISIBLE);
				mHasSummaryContent = true;
			}
			else
			{
				mAbstract.setVisibility(View.GONE);
			}

			final View requirementsBlock = findViewById(R.id.session_requirements_block);
			final String sessionRequirements = cursor.getString(SessionsQuery.REQUIREMENTS);
			
			if (!TextUtils.isEmpty(sessionRequirements))
			{
				UIUtils.setTextMaybeHtml(mRequirements, sessionRequirements);
				requirementsBlock.setVisibility(View.VISIBLE);
				mHasSummaryContent = true;
			}
			else
			{
				requirementsBlock.setVisibility(View.GONE);
			}

			//setupModeratorTab(cursor);

			// Show empty message when all data is loaded, and nothing to show
			if (mSpeakersCursor && !mHasSummaryContent)
			{
				findViewById(android.R.id.empty).setVisibility(View.VISIBLE);
			}
		}
		finally
		{
			cursor.close();
		}
	}

	/** Handle {@link TracksQuery} {@link Cursor}. */
	private void onTrackQueryComplete(Cursor cursor)
	{
		try
		{
			if (!cursor.moveToFirst())
				return;

			// Use found track to build title-bar
			((TextView) findViewById(R.id.title_text)).setText(cursor.getString(TracksQuery.TRACK_NAME));
			UIUtils.setTitleBarColor(findViewById(R.id.title_container), cursor.getInt(TracksQuery.TRACK_COLOR));
		}
		finally
		{
			cursor.close();
		}
	}

	private void onSpeakersQueryComplete(Cursor cursor)
	{
		try
		{
			mSpeakersCursor = true;

			final ViewGroup speakersGroup = (ViewGroup) findViewById(R.id.session_speakers_block);
			final LayoutInflater inflater = getLayoutInflater();

			boolean hasSpeakers = false;

			while (cursor.moveToNext())
			{
				final String speakerName = cursor.getString(SpeakersQuery.SPEAKER_NAME);
				final String speakerCompany = cursor.getString(SpeakersQuery.SPEAKER_COMPANY);
				
				if (TextUtils.isEmpty(speakerName))
					continue;

				final View speakerView = inflater.inflate(R.layout.speaker_detail, speakersGroup, false);

				final String speaker = getString(R.string.speaker_template, speakerName, speakerCompany);
				((TextView) speakerView.findViewById(R.id.speaker_header)).setText(speaker);

				final String speakerAbstract = cursor.getString(SpeakersQuery.SPEAKER_ABSTRACT);
				final TextView abstractView = (TextView) speakerView.findViewById(R.id.speaker_abstract);
				UIUtils.setTextMaybeHtml(abstractView, speakerAbstract);

				speakersGroup.addView(speakerView);
				hasSpeakers = true;
				mHasSummaryContent = true;
			}

			speakersGroup.setVisibility(hasSpeakers ? View.VISIBLE : View.GONE);

			// Show empty message when all data is loaded, and nothing to show
			if (mSessionCursor && !mHasSummaryContent)
			{
				findViewById(android.R.id.empty).setVisibility(View.VISIBLE);
			}

		}
		finally
		{
			cursor.close();
		}
	}

	/** Handle "home" title-bar action. */
	public void onHomeClick(View v)
	{
		UIUtils.goHome(this);
	}

	/** Handle "share" title-bar action. */
	public void onShareClick(View v)
	{
		final String shareString = getString(R.string.share_template, mTitleString, mHashtag);
		final Intent intent = new Intent(Intent.ACTION_SEND);
		
		intent.setType("text/plain");
		intent.putExtra(Intent.EXTRA_TEXT, shareString);

		startActivity(Intent.createChooser(intent, getText(R.string.title_share)));
	}

	/** Handle "map" title-bar action. */
	public void onMapClick(View v)
	{
		final Intent intent = new Intent(this, MapActivity.class);
		
		if (mRoomId != null && mRoomId.startsWith("officehours"))
		{
			intent.putExtra(MapActivity.EXTRA_ROOM, MapActivity.OFFICE_HOURS_ROOM_ID);
		}
		else
		{
			intent.putExtra(MapActivity.EXTRA_ROOM, mRoomId);
		}
		
		startActivity(intent);
	}

	/** Handle "search" title-bar action. */
	public void onSearchClick(View v)
	{
		UIUtils.goSearch(this);
	}

	/** Handle toggling of starred checkbox. */
	public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
	{
		final ContentValues values = new ContentValues();
		
		values.put(Vendors.STARRED, isChecked ? 1 : 0);
		mHandler.startUpdate(mSessionUri, values);
	}

	private static HttpClient sHttpClient;

	private static synchronized HttpClient getHttpClient(Context context)
	{
		if (sHttpClient == null)
		{
			sHttpClient = SyncService.getHttpClient(context);
		}
		
		return sHttpClient;
	}

//	private void startModeratorStatusFetch(String moderatorLink)
//	{
//		try
//		{
//			// Extract series and topic from moderator link
//			// NOTE: this makes some ugly assumptions that the "t=" parameter
//			// occurs at the end of the URL.
//			final String clause = moderatorLink.substring(moderatorLink.indexOf("t=") + 2);
//
//			final int dotIndex = clause.indexOf('.');
//			final int seriesId = Integer.parseInt(clause.substring(0, dotIndex), 16);
//			final int topicId = Integer.parseInt(clause.substring(dotIndex + 1), 16);
//
//			// Kick off background request to find current status
//			final String remoteUrl = "http://www.googleapis.com/moderator/v1/series/" + seriesId + "/topics/" + topicId;
//			
//			new ModeratorStatusTask().execute(remoteUrl);
//
//		}
//		catch (Exception e)
//		{
//			Log.w(TAG, "Problem while parsing Moderator URL", e);
//		}
//	}

	@SuppressWarnings("unused")
	private class ModeratorStatusTask extends AsyncTask<String, Void, String>
	{
		@Override
		protected String doInBackground(String... params)
		{
			final String param = params[0];

			try
			{
				final Context context = SessionDetailActivity.this;
				final HttpClient httpClient = getHttpClient(context);
				final HttpResponse resp = httpClient.execute(new HttpGet(param));
				final HttpEntity entity = resp.getEntity();
				
				final int statusCode = resp.getStatusLine().getStatusCode();
				
				if (statusCode != HttpStatus.SC_OK || entity == null)
					return null;

				final String respString = EntityUtils.toString(entity);
				final JSONObject respJson = new JSONObject(respString);

//				@SuppressWarnings("unused")
				final JSONObject data = respJson.getJSONObject("data");
				final JSONObject counters = respJson.getJSONObject("counters");

				final int questions = counters.getInt("submissions");
				final int votes = counters.getInt("noteVotes") + counters.getInt("plusVotes")
						+ counters.getInt("minusVotes");

				return getString(R.string.session_moderator_status, questions, votes);
			}
			catch (Exception e)
			{
				Log.w(TAG, "Problem while loading Moderator status: " + e.toString());
			}
			
			return null;
		}

		@Override
		protected void onPostExecute(String result)
		{
			final TextView status = (TextView) findViewById(R.id.moderator_status);
			
			if (result == null)
			{
				status.setVisibility(View.GONE);
			}
			else
			{
				status.setVisibility(View.VISIBLE);
				status.setText(result);
			}
		}
	}

	/** {@link Sessions} query parameters. */
	private interface SessionsQuery
	{
		int _TOKEN = 0x1;

		String[] PROJECTION =
		{ Blocks.BLOCK_START, Blocks.BLOCK_END, Sessions.TYPE, Sessions.TITLE, Sessions.ABSTRACT,
				Sessions.REQUIREMENTS, Sessions.STARRED, Sessions.MODERATOR_URL, Sessions.WAVE_URL, Sessions.ROOM_ID,
				Sessions.HASHTAG, Rooms.ROOM_NAME, };

		int BLOCK_START = 0;
		int BLOCK_END = 1;
		@SuppressWarnings("unused")
		int TYPE = 2;
		int TITLE = 3;
		int ABSTRACT = 4;
		int REQUIREMENTS = 5;
		int STARRED = 6;
		@SuppressWarnings("unused")
		int MODERATOR_LINK = 7;
		@SuppressWarnings("unused")
		int WAVE_LINK = 8;
		int ROOM_ID = 9;
		int HASHTAG = 10;
		int ROOM_NAME = 11;
	}

	/** {@link Tracks} query parameters. */
	private interface TracksQuery
	{
		int _TOKEN = 0x2;

		String[] PROJECTION =
		{ Tracks.TRACK_NAME, Tracks.TRACK_COLOR, };

		int TRACK_NAME = 0;
		int TRACK_COLOR = 1;
	}

	private interface SpeakersQuery
	{
		int _TOKEN = 0x3;

		String[] PROJECTION =
		{ Speakers.SPEAKER_NAME, Speakers.SPEAKER_COMPANY, Speakers.SPEAKER_ABSTRACT, };

		int SPEAKER_NAME = 0;
		int SPEAKER_COMPANY = 1;
		int SPEAKER_ABSTRACT = 2;
	}
}
